package com.sevntu.apvs.lab2;

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;

public class CoverTable {

	//data from interv file
	private static int varNumber = 0;
	private static int intervNumber = 0;
	private static List<Integer> intervArrayHigh = null;
	private static List<Integer> intervArrayLow = null;

	//data from sysfun file
	private static int numberOfOneSet = 0;
	//private static int numberOfXSet = 0;
	private static List<Integer> setList = null;

	//table of cover
	private static int[][] tableCover = null;

	//source files names
	//private static final String SYS_FUN_FILE_NAME = "sysfun2.bin";
	//private static final String INTERV_FILE_NAME = "interv2.bin";
	//private static final String TABLE_COVER_FILE_NAME = "tablecover2.bin";
	//private static final String TABLE_COVER_FILE_NAME_TXT = "tablecover2.txt";

	public CoverTable() {
		initTableCover();
	}

	public static void main(String[] args) {

		InputStream sysFun = null;
		InputStream intervList = null;
		CoverTable classObj = new CoverTable();
		OutputStream tableCoverFile = null;
		BufferedWriter tableCoverFileTXT = null;

		try {
			//sysFun = new FileInputStream(SYS_FUN_FILE_NAME);
			//intervList = new FileInputStream(INTERV_FILE_NAME);
			//tableCoverFile = new FileOutputStream(TABLE_COVER_FILE_NAME);
			//tableCoverFileTXT = new BufferedWriter(new FileWriter(TABLE_COVER_FILE_NAME_TXT));

			sysFun = new FileInputStream(args[0]);
			intervList = new FileInputStream(args[1]);
			tableCoverFile = new FileOutputStream(args[2]);
			tableCoverFileTXT = new BufferedWriter(new FileWriter(args[3]));

			classObj.getDataFromSysFunFile(sysFun);
			classObj.getDataFromIntervFile(intervList);
			tableCover = new int[intervNumber][numberOfOneSet];
			classObj.fillTableCover();
			classObj.printTableCoverToFile(tableCoverFile, tableCoverFileTXT);

		} catch (FileNotFoundException e) {

		} catch (IOException e) {
			e.getMessage();

		} finally {
			try {
				if (sysFun != null)
					sysFun.close();
				if (intervList != null)
					intervList.close();
				if (tableCoverFile != null)
					tableCoverFile.close();
				if (tableCoverFileTXT != null)
					tableCoverFileTXT.close();
			} catch (IOException e) {

			}
		}
	}

	private void initTableCover() {
		for (int i = 0; i < intervNumber; i++) {
			for (int j = 0; j < varNumber; j++) {
				tableCover[i][j] = 0;
			}
		}
	}

	private void fillTableCover() {

		int[] interval = new int[varNumber];
		int decode = -1;
		int intervShift = 0;
		int[] bitsOfSet = new int[varNumber];
		boolean isSetBelongToInterv = true;

		for (int i = 0; i < intervNumber; i++) {
			for (int j = 0, countInter = 0; j < varNumber; j++, countInter++) {
				decode = decodeIntervVar(intervArrayHigh.get(j + intervShift), intervArrayLow.get(j + intervShift));
				interval[countInter] = decode;
			}
			for (int k = 0; k < numberOfOneSet; k++) {
				bitsOfSet = getBitsOfSet(k);
				for (int varCount = 0; varCount < varNumber; varCount++) {
					if (interval[varCount] == -1)
						continue;
					else if (interval[varCount] != bitsOfSet[varCount]) {
						isSetBelongToInterv = false;
						break;
					}
				}
				if (isSetBelongToInterv) {
					tableCover[i][k] = 1;
				}
				isSetBelongToInterv = true;
			}
			intervShift += varNumber;
		}
	}

	private int decodeIntervVar(int high, int low) {
		if (high == 0 && low == 1)
			return 0;
		else if (high == 1 && low == 0)
			return 1;
		return -1;
	}

	private int[] getBitsOfSet(int indexInSet) {
		int[] bitsOfSet = new int[varNumber];
		int readByteFromSet = setList.get(indexInSet);

		for (int i = 0; i < varNumber; i++) {
			bitsOfSet[i] = readByteFromSet & 0x01;
			readByteFromSet >>= 1;
		}
		return bitsOfSet;
	}

	private void getDataFromSysFunFile(InputStream sysFun) throws IOException {

		setList = new LinkedList<Integer>();
		int tempRead = 0;

		//pass 4 bytes (var numbers, fun numbers)
		for (int i = 0; i < 4; i++) {
			sysFun.read();
		}
		numberOfOneSet = sysFun.read();
		sysFun.read();
		//numberOfXSet = sysFun.read();
		sysFun.read();
		sysFun.read();

		for (int i = 0; i < numberOfOneSet; i++) {
			tempRead = sysFun.read();
			if (tempRead != -1) {
				setList.add(tempRead);
			} else
				continue;
			tempRead = sysFun.read();
		}
	}

	private void getDataFromIntervFile(InputStream intervList) throws IOException {

		intervArrayHigh = new LinkedList<Integer>();
		intervArrayLow = new LinkedList<Integer>();
		int tempRead = 0;
		boolean isHighOrLow = true;

		intervNumber = intervList.read();
		intervList.read();
		varNumber = intervList.read();
		intervList.read();

		while (tempRead != -1) {
			tempRead = intervList.read();
			if (tempRead != -1) {
				if (isHighOrLow) {
					intervArrayHigh.add(tempRead);
					isHighOrLow = false;
				} else {
					intervArrayLow.add(tempRead);
					isHighOrLow = true;
				}
			} else
				continue;
			tempRead = intervList.read();
		}
	}

	private void printTableCoverToFile(OutputStream tableCoverFile, BufferedWriter tableCoverFileTXT)
			throws IOException {
		byte[] tableCoverToFile = new byte[intervNumber * numberOfOneSet * 2];
		int tableCoverCount = 0;

		tableCoverFileTXT.write(intervNumber + " " + numberOfOneSet + '\n');

		for (int i = 0; i < intervNumber; i++) {
			for (int j = 0; j < numberOfOneSet; j++) {
				tableCoverToFile[tableCoverCount] = (byte) tableCover[i][j];
				tableCoverCount++;
				tableCoverToFile[tableCoverCount] = 0;
				tableCoverCount++;

				tableCoverFileTXT.write(tableCover[i][j] + " ");
			}
			tableCoverFileTXT.write('\n');
		}
		tableCoverFile.write(intervNumber);
		tableCoverFile.write(0);
		tableCoverFile.write(numberOfOneSet);
		tableCoverFile.write(0);
		tableCoverFile.write(tableCoverToFile);
	}
}
